package com.cordys.opensource.crom.sql;

import com.cordys.cpc.bsf.busobject.BusObject;
import com.cordys.cpc.bsf.classinfo.AttributeInfo;
import com.cordys.cpc.bsf.classinfo.ClassInfo;

/**
 * Indicates a column of a table.
 * It can be either part of the select clause or not.
 * It can have an alias.
 */
public class Column
{
	private final String sColumnName;
	private final String sAliasName;
	private final Table table;
	private final Query query;

	// Ordering and selection may change.
	private Order ordering = Order.NONE; // By default do not order on this column.
	private boolean isSelected = true;
	private boolean useQuotes = true;

	/**
	 * @param query The query to which the column belongs.
	 * @param table The table to which the column belongs
	 * @param columnName The name of the column
	 * @param aliasName The alias name for the column. Can be null.
	 * @param isSelected Determines whether the column is part of the select statement or not. If not, then the column may be part of e.g. the where clause or the order clause.
	 */
	public Column(Query query, Table table, String columnName, String aliasName, boolean isSelected)
	{
		this.table = table;
		this.sColumnName = columnName;
		this.query = query;
		this.sAliasName = aliasName==null?"":aliasName;
		this.isSelected = isSelected;
	}

	/**
	 * Makes the column part of the select statement.
	 * Sometimes a column need not be part of the select statement, e.g. when it is used in a where expression.
	 */
	public Column select()
	{
		this.isSelected = true;
		return this;
	}
	
	Query getQuery()
	{
		return query;
	}
	
	/**
	 * Determine whether this column should be escaped in the query using quote characters.
	 * Note: by default the column fields are escaped, so this method only needs to be used if you do not want to use quotes on the column.
	 * @param useQuotes If true, the column name and alias will be escaped in the query text.
	 */
	public void setUseQuotes(boolean useQuotes)
	{
		this.useQuotes = useQuotes;
	}
	
	/**
	 * Returns whether this column should be escaped in the query using quote characters
	 * @return
	 */
	public boolean usesQuotes()
	{
		return useQuotes;
	}
	
	/**
	 * Removes the column from the select statement.
	 * Sometimes a column need not be part of the select statement, e.g. when it is used in a where expression.
	 */
	public void deselect()
	{
		this.isSelected = false;
	}
	
	/**
	 * Indicates whether the column is part of the select statement.
	 * Sometimes a column need not be part of the select statement, e.g. when it is used in a where expression.
	 */
	public boolean isSelected()
	{
		return this.isSelected;
	}
	
	/**
	 * Sets (or removes) ordering for this column.
	 * @param ordering If Order.NONE is specified, the column will not participate in the Order By clause.
	 * Other possible values are Order.ASCENDING and Order.DESCENDING.
	 */
	public void setOrdering(Order ordering)
	{
		this.ordering = ordering;
		query.addOrder(this);
	}
	
	/**
	 * Returns the ordering of the column. If the column does not participate in the Order By clause,
	 * then Order.NONE will be returned.
	 * @return
	 */
	public Order getOrdering()
	{
		return ordering;
	}
    
	/**
	 * Gives the from to which this column belongs.
	 * @return
	 */
	public Table getTable()
	{
		return table;
	}
	
	/**
	 * Returns the WS-AppServer AttributeInfo for this column, if available. Else returns null.
	 * @return
	 */
	AttributeInfo getAttributeInfo()
	{
		Class<? extends BusObject> persistenceClass = table.getPersistenceClass();
		ClassInfo classInfo = BusObject._getClassInfo(persistenceClass);
		AttributeInfo attribute = classInfo.getAttributeInfo(sColumnName);
		return attribute;
	}

	/**
	 * Returns the name of the column.
	 * @return
	 */
	public String getColumnName()
	{
		return sColumnName;
	}

	/**
	 * Returns the alias of the column.
	 * @return
	 */
	public String getAliasName() {
		return sAliasName;
	}
	
	private void addQuote(StringBuilder sb)
	{
		if (useQuotes)
		{
			sb.append("\"");
		}
	}

	/**
	 * Returns a string representation of the column.
	 */
	public String toString()
	{
		StringBuilder sb = new StringBuilder();
		sb.append(table.getAliasName() + ".");
		addQuote(sb);
		sb.append(sColumnName);
		addQuote(sb);
		return sb.toString();
	}
	
	public String getUnaliasedString()
	{
		StringBuilder sb = new StringBuilder();
		sb.append(table.getAliasName() + ".");
		addQuote(sb);
		sb.append(sColumnName);
		addQuote(sb);
		if (sAliasName!="")
		{
			sb.append(" as ");
			addQuote(sb);
			sb.append(sAliasName);
			addQuote(sb);
		}
		return sb.toString();
	}

	/**
	 * Compare two columns whether they have the same alias name and same table.
	 */
	public boolean equals(Object that)
	{
		if (this==that) return true;
		if (that==null) return false;
		if (! (that instanceof Column)) return false;
		
    	if (! this.getAliasName().equals(((Column)that).getAliasName())) return false;
    	if (! this.table.equals(((Column)that).table)) return false;

    	return true;
	}
}
